home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / zmdm / expandar.c < prev    next >
C/C++ Source or Header  |  1993-06-26  |  15KB  |  694 lines

  1.  
  2.     /* 
  3.      *     Examine each argument given to expandargs()
  4.      *     If it is a directory, then expand it
  5.      *    to all its component files, recursively
  6.      *    till you bottom out.
  7.      *    If it is not a directory, then just pass it on.
  8.      *
  9.      *    Inputs: routine, argc, argv
  10.      *    Outputs: nargc, nargv (calls routine(nargc, nargv))
  11.      *    To test: compile with -DTEST
  12.      *         define MWC if using Mark Williams C
  13.      *         run with a directory as an arg
  14.      *    Author: JRB
  15.      *    Requirements: Mark Williams C or Alcyon C
  16.      *        Wants lots of Dynamic memory. It
  17.      *        all depends upon how many files you
  18.      *        have. Use the -P option to prune
  19.      *        out subdirectories and do things
  20.      *        one at a time, if you keep running
  21.      *        out of memory.
  22.      *        With Mark Williams i use _stksize = 128K
  23.      *        With Alcyon i use memory model 2 (half of
  24.      *        of avail memory) in GEMSTART.S
  25.      *
  26.          *      WARNINGS: Be CAREFUL about the 40 folder bug. Use
  27.      *              GEMBOOT or FOLDRXXX when dealing with
  28.      *          a deeply nested file structure.
  29.      *
  30.      *    Added -P name prune option at the suggestion of dietz@zhmti
  31.      *    Multiple -P's may be given on the command line.
  32.      *    -P name may be given anywhere on the command line. -P name
  33.      *    will prune the subdirectories named as arguement to -P.
  34.      *    ie: when the program is decending the file hierarchy it
  35.      *    will not visit the pruned branches.
  36.      *     NOTE that the option is -P and not -p
  37.      *          (-p is a valid sz option).
  38.      *    NOTE that the arguement given to -P can be the name
  39.      *     of a file or a directory. In case it is a file,
  40.      *    that file is skipped.
  41.      *
  42.      */
  43.  
  44. /*
  45.  * Expand argc, so that the called routine(nargc,nargv) receives only
  46.  * filenames, in nargv[][]
  47.  *
  48.  ************************************************************************
  49.  *                                    *
  50.  *      WARNING:  Be CAREFUL about the 40 folder bug. Use        *
  51.  *              GEMBOOT or FOLDRXXX when dealing with            *
  52.  *          a deeply nested file structure.            *
  53.  *                                    *
  54.  ************************************************************************
  55.  *
  56.  *    Jwahar R. Bammi
  57.  *    usenet: {decvax,cbosgd,sun}!cwruecmp!bammi
  58.  *    csnet:       bammi@cwru.edu
  59.  *    arpa:        bammi@cwru.edu
  60.  *    compuServe:  71515,155
  61.  *
  62.  */
  63. #ifdef TEST
  64. #include <stdio.h>
  65. #include <osbind.h>
  66. #include <ctype.h>
  67. #endif
  68.  
  69. #ifdef TRUE
  70. #undef TRUE
  71. #endif
  72. #ifdef OK
  73. #undef OK
  74. #endif
  75. #ifdef FALSE
  76. #undef FALSE
  77. #endif
  78.  
  79. #define TRUE     1
  80. #define OK     0
  81. #define FALSE     0
  82. #define Realloc     realloc
  83.  
  84. #ifdef TEST
  85. struct    stat
  86. {
  87.     char    st_sp1[21];    /* Junk        */
  88.     char    st_mode;       /* File attributes */
  89.     int    st_time;       /* Mod Time      */
  90.     int     st_date;       /* Mod date      */
  91.     long    st_size;       /* File size       */
  92.     char    st_name[14];   /* File name       */
  93. };
  94. #endif
  95.  
  96. typedef struct _prunelist {
  97.     char *name;            /* name of subdirectory to prune */
  98.     struct _prunelist *next;    /* ptr to next */
  99. } PRUNELIST;
  100.  
  101. static char *ProgName;
  102. static PRUNELIST *PruneList = (PRUNELIST *)NULL; /* Head of PruneList */
  103.  
  104. static char **CopyToNargv();
  105. static char **ExpandStack();
  106. static void FreeStack();
  107. static void FreeNargv();
  108. static void FreePrune();
  109. static void FreeUp();
  110. static int PushDir();
  111. static char *PopDir();
  112. static int ProcessDirs();
  113. static PRUNELIST *AddPrune();
  114. static int OnPruneList();
  115. static int isdir();
  116.  
  117. extern int existd();
  118.  
  119. expandargs(routine, argc, argv)
  120. int (*routine)();
  121. int argc;
  122. char **argv;
  123. {
  124.     register int status;
  125.     int nargc;
  126.     char **nargv;
  127.     extern char **CopyToNargv();
  128.     extern PRUNELIST *AddPrune();
  129.     extern int existd();
  130.  
  131.     nargc = 0;
  132.     nargv = (char **)NULL;
  133.     ProgName = *argv;
  134.     
  135.     /* copy argv[0] blindly */
  136.     if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL)
  137.     {
  138.         FreeUp(nargc, nargv);
  139.         return(~OK);
  140.     }
  141.  
  142.     nargc++;
  143.     
  144.     while((--argc) > 0)
  145.     {
  146.         argv++;
  147.         if(**argv == '-')
  148.         {
  149.             /* copy any options except -P */
  150. #ifdef TEST
  151.             /* some shell pass -P as -p */
  152.             if( ((*argv)[1] == 'P') || ((*argv)[1] == 'p'))
  153. #else
  154.             if( (*argv)[1] == 'P')
  155. #endif
  156.             {
  157.                 if((--argc) <= 0)
  158.                 {
  159.                     fprintf(stderr,"no argument given to -P\n");
  160.                     FreeUp(nargc, nargv);
  161.                     return(~OK);
  162.                 }
  163.                 if((PruneList = AddPrune(PruneList,*++argv))
  164.                    == (PRUNELIST *)NULL)
  165.                 {
  166.                     FreeUp(nargc, nargv);
  167.                     return(~OK);
  168.                 }
  169.             }
  170.             else
  171.             {
  172.                 if((nargv = CopyToNargv(*argv, nargc, nargv))
  173.                    == (char **)NULL)
  174.                 {
  175.                     FreeUp(nargc, nargv);
  176.                     return(~OK);
  177.                 }
  178.                 else
  179.                     nargc++;
  180.             }
  181.             
  182.         }
  183.         else
  184.         {
  185.             /* If its not on the PruneList then */
  186.             if(!OnPruneList(PruneList, *argv))
  187.             {
  188.                 /* if it is a directory, push it */
  189.                 if(existd(*argv))
  190.                 {
  191.                     if((status = PushDir(*argv)) != OK)
  192.                     {
  193.                         FreeUp(nargc, nargv);
  194.                         return(status);
  195.                     }
  196.                 }
  197.                 else
  198.                 {
  199.                     /* it is NOT a directory, copy to nargv */
  200.                     if((nargv = CopyToNargv(*argv, nargc, nargv))
  201.                        == (char **)NULL)
  202.                     {
  203.                         FreeUp(nargc, nargv);
  204.                         return(~OK);
  205.                     }
  206.                     else
  207.                         nargc++;
  208.                 }
  209.             }
  210.         }
  211.     } /* while */
  212.  
  213.     /* process pushed directories if any */
  214.     if((status = ProcessDirs(&nargc, &nargv)) != OK)
  215.     {
  216.         FreeUp(nargc, nargv);
  217.         return(status);
  218.     }
  219.     /* else Free the Stack and Prune List, call *routine */
  220.     FreeStack();
  221.     FreePrune();
  222.     status =  (*routine)(nargc, nargv);
  223.     FreeNargv(nargc, nargv);
  224.  
  225.     return status;
  226.  
  227. }
  228.  
  229. /*
  230.  * Expand nargv by an element and copy a String into the new element
  231.  *
  232.  */
  233. static char **CopyToNargv(string, nargc, nargv)
  234. char *string;
  235. int nargc;
  236. char **nargv;
  237. {
  238.     extern char *malloc(), *Realloc(), *strcpy();
  239.     extern int strlen();
  240.     
  241.     /* expand nargv by 1 element */
  242.     if(nargv == (char **)NULL)
  243.         /* do it with malloc for the first one */
  244.         nargv = (char **)malloc(sizeof(char **));
  245.     else
  246.         /* do it with Realloc for others */
  247.         nargv = (char **)Realloc(nargv, (nargc+1)*sizeof(char **));
  248.     
  249.     if(nargv == (char **)NULL)
  250.     {
  251.         /* failed to get memory */
  252.         fprintf(stderr,"%s(CopyToNargv()): Out of Memory\n", ProgName);
  253.         return ((char **)NULL);
  254.     }
  255.  
  256.     /* Get mem for string */
  257.     if(( nargv[nargc] = malloc(strlen(string)+1)) == (char *)NULL)
  258.     {
  259.         /* failed to get memory */
  260.         fprintf(stderr,"%s(CopyToNargv()): Out of Memory\n", ProgName);
  261.         return ((char **)NULL);
  262.     }
  263.  
  264.     /* copy string into nargv[nargc] */
  265.     (void)strcpy( nargv[nargc], string);
  266.     return(nargv);
  267. }
  268.  
  269. static char **Stack = (char **)NULL;    /* directory stack */
  270. static char StackSize = 0;        /* Size of current Stack */
  271. static int    Top   = -1;
  272. #define STACK_EMPTY    (Top < 0)
  273. #define CHUNKSIZE    16
  274.  
  275. /*
  276.  * Grow the Stack by one chunk of CHUNKSIZE elements
  277.  *
  278.  */
  279. static char **ExpandStack(Stack)
  280. char **Stack;
  281. {
  282.     extern char *malloc(), *Realloc();
  283.     
  284.     /* Grow Stack */
  285.     if(Stack == (char **)NULL)
  286.         /* with malloc */
  287.         Stack = (char **)malloc(CHUNKSIZE * sizeof(char **));
  288.     else
  289.         /* with Realloc */
  290.         Stack = (char **)Realloc(Stack, (StackSize+CHUNKSIZE) *
  291.                              sizeof(char **));
  292.  
  293.     if(Stack == (char **)NULL)
  294.     {
  295.         /* outa mem */
  296.         fprintf(stderr,"%s(ExpandStack()): Out of Memory\n", ProgName);
  297.         return((char **)NULL);
  298.     }
  299.     StackSize += CHUNKSIZE;
  300.     return(Stack);
  301. }
  302.  
  303. /*
  304.  * Free the Stack
  305.  *
  306.  */
  307. static void FreeStack()
  308. {
  309.     if(StackSize > 0)
  310.         (void)free(Stack);
  311.     Stack = (char **)NULL;
  312.     StackSize = 0;
  313.     Top   = -1;
  314. }
  315.  
  316. /*
  317.  * Free Nargv
  318.  *
  319.  */
  320. static void FreeNargv(nargc, nargv)
  321. int nargc;
  322. char *nargv[];
  323. {
  324.     register int i;
  325.  
  326.     for(i = 0; i < nargc; i++)
  327.         (void)free(nargv[i]);
  328.     if(nargc > 0)
  329.         (void)free(nargv);
  330. }
  331.  
  332. /*
  333.  * Free the PruneList
  334.  *
  335.  */
  336. static void FreePrune()
  337. {
  338.     register PRUNELIST *p, *next;
  339.  
  340.     for(p = PruneList; p != (PRUNELIST *)NULL; p = next)
  341.     {
  342.         next = p->next;
  343.         (void)free(p);
  344.     }
  345.     PruneList = (PRUNELIST *)NULL;
  346. }
  347.  
  348. /*
  349.  * FreeUp before bad exit
  350.  *
  351.  */
  352. static void FreeUp(nargc, nargv)
  353. int nargc;
  354. char **nargv;
  355. {
  356.     FreeStack();
  357.     FreePrune();
  358.     FreeNargv(nargc, nargv);
  359. }
  360.  
  361. /*
  362.  * Push a directory name on Stack
  363.  *
  364.  */
  365. static int PushDir(name)
  366. char *name;
  367. {
  368.     extern char *malloc(), *strcpy();
  369.     extern int strlen();
  370.     extern char **ExpandStack();
  371.  
  372. #ifdef DDEBUG
  373. printf("PushDir: %s\n", name);
  374. #endif
  375.  
  376.     ++Top;
  377.     if(Top >= StackSize)
  378.     {
  379.         if((Stack = ExpandStack(Stack)) == (char **)NULL)
  380.             return(~OK);
  381.     }
  382.     
  383.     if((Stack[Top] = malloc(strlen(name)+1)) == (char *)NULL)
  384.     {
  385.         /* outa mem */
  386.         fprintf(stderr,"%s(PushDir()): Out of Memory\n", ProgName);
  387.         return(~OK);
  388.     }
  389.     (void)strcpy(Stack[Top], name);
  390.     return(OK);
  391. }
  392.  
  393. /*
  394.  * Pop a directory name from the stack
  395.  *
  396.  */
  397. static char *PopDir()
  398. {
  399.     register char *r;
  400.     extern char **ShrinkStack();
  401.     
  402.     if(STACK_EMPTY)
  403.         return ((char *)NULL);
  404.     
  405.     r = Stack[Top];
  406.     Top--;
  407.     return(r);
  408. }
  409.  
  410. static int BadStatus = FALSE;
  411. #define BADSTATUS (BadStatus != FALSE)
  412. #define MAXNAMLEN 128
  413.  
  414. /*
  415.  * Process directories on the Stack, by adding all the
  416.  * files in a directory to nargv.
  417.  */
  418. static int ProcessDirs(nargc, nargv)
  419. int *nargc;
  420. char ***nargv;
  421. {
  422.     register char *name;
  423.     register struct stat *dp;
  424.     register int status, slashp;
  425.     char path[MAXNAMLEN+1];
  426.     extern char **CopyToNargv();
  427.     extern char *PopDir();
  428.     extern char *alltolower();
  429.     
  430.     if(BADSTATUS)
  431.         return(~OK);
  432.  
  433.     if(STACK_EMPTY)
  434.         /* Nothing more to do */
  435.         return(OK);
  436.  
  437.     /* Pop a directory from Stack and process */
  438.     if((name = PopDir()) == (char *)NULL)
  439.     {
  440.         /* Oh Oh */
  441.         fprintf(stderr,"Internal Error (BUG), PopDir returns NULL\n");
  442.         BadStatus = (~FALSE);
  443.         return(~OK);
  444.     }
  445.     
  446.     strcpy(path, name);
  447.     if(path[(strlen(path)-1)] == '\\')
  448.     {
  449.         strcat(path,"*.*");
  450.         slashp = TRUE;
  451.     }
  452.     else
  453.     {
  454.         strcat(path,"\\*.*");
  455.         slashp = FALSE;
  456.     }
  457.         
  458.     /* Open the directory */
  459.     if(Fsfirst(path, 0x0020| 0x0010 | 0x0001) != 0)
  460.     {
  461.         /* trouble opening directory */
  462.         fprintf(stderr,"Trouble opening %s\n",path);
  463.         /* set BADSTATUS and return */
  464.         BadStatus = (~FALSE);
  465.         return(~OK);
  466.     }
  467.  
  468.     /* get the DTA */
  469.     dp = (struct stat *)Fgetdta();
  470.     
  471.     /* for each entry in the directory, if it is a file
  472.        add to nargv. If it is a directory, Push it onto
  473.        the directory stack.
  474.      */
  475.     do
  476.     {
  477.         if(! ((strcmp(dp->st_name,".") == 0) ||
  478.               (strcmp(dp->st_name,"..") == 0)) )
  479.         {
  480.             strcpy(path, name);
  481.             if(!slashp)
  482.                 strcat(path,"\\");
  483.             strcat(path,dp->st_name);
  484.  
  485.             /* If this path is on the PruneList skip */
  486.             if(OnPruneList(PruneList, alltolower(path)))
  487.                 continue;
  488.  
  489.             if(!isdir(path, dp->st_mode))
  490.             {
  491.                 /* not a dir -- add this to nargv */
  492.                 if((*nargv = CopyToNargv(path, *nargc, *nargv))
  493.                     == (char **)NULL)
  494.                 {
  495.                     BadStatus = (~FALSE);
  496.                     return(~OK);
  497.                 }
  498.                 else
  499.                 {
  500.                     *nargc += 1;
  501.                 }
  502.                 
  503.             }
  504.             else
  505.             {
  506.  
  507.                 /* Push This directory */
  508.                 if((status = PushDir(path)) != OK)
  509.                 {
  510.                     BadStatus = (~FALSE);
  511.                     return(status);
  512.                 }
  513.             }
  514.         }
  515.     } while(Fsnext() == 0);
  516.  
  517.     free(name);    /* done with this directory */
  518.     
  519.     /* go do the rest */
  520.     return (ProcessDirs(nargc, nargv));
  521. }
  522.  
  523. /*
  524.  * Add a name to PruneList
  525.  *
  526.  */
  527. static PRUNELIST *AddPrune(list, name)
  528. PRUNELIST *list;
  529. char *name;
  530. {
  531.     extern char *malloc();
  532.     register PRUNELIST *new;
  533.     
  534.     if((new = (PRUNELIST *)malloc(sizeof(PRUNELIST))) == (PRUNELIST *)NULL)
  535.     {
  536.         /* outa mem */
  537.         fprintf(stderr,"%s(AddPrune()): Out of Memory\n", ProgName);
  538.         return(new);
  539.     }
  540.  
  541.     new->name = name;
  542.     new->next = list;
  543.     
  544.     return(new);
  545. }
  546.  
  547. /*
  548.  * Search for name on PruneList
  549.  *
  550.  */
  551. static int OnPruneList(list, name)
  552. register PRUNELIST *list;
  553. register char *name;        
  554. {
  555.     for(; list != (PRUNELIST *)NULL; list = list->next)
  556.     {
  557.         if(strcmp(list->name, name) == 0)
  558.             return(~FALSE);
  559.     }
  560.     
  561.     return(FALSE);
  562. }
  563.  
  564. /*
  565.  * test if a subdirectory exists, without touching the DTA
  566.  * include special case of 'D:\' that Fsfirst does'nt handle correctly
  567.  */
  568. static int isdir(name, attr)
  569. register char *name;
  570. register int attr;
  571. {
  572.     /* assuming the DTA buffer is already set up */
  573.     extern long drv_map;
  574.     register int drive;
  575.     
  576.     if(attr & 0x0010)
  577.         return TRUE;
  578.  
  579.     /* Gemdos doesn't like d:\ style dirs */
  580.     if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
  581.     {
  582.         drive = name[0];
  583.         if(isupper(drive))
  584.             drive = tolower(drive);
  585.  
  586.         drive = drive - 'a';
  587.         if((drv_map & (1L << drive)) == 0)
  588.             return FALSE;
  589.         else
  590.             return TRUE;
  591.     }
  592.     /* Nor does Gemdos understand '.' or '..' */
  593.     /* Hey Atari, don't you guys ever test anything */
  594.     if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
  595.        (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
  596.         return TRUE;
  597.  
  598.     return FALSE;
  599. }
  600.  
  601.  
  602. #ifdef TEST
  603.  
  604. /*
  605.  * convert string to all lower case
  606.  */
  607. char *alltolower(s)
  608. char *s;
  609. {
  610.     register char *p;
  611.  
  612.     for(p = s; *p != '\0'; p++)
  613.         if(isupper(*p))
  614.             *p = tolower(*p);
  615.  
  616.     return s;
  617. }
  618.     
  619. /*
  620.  * test if a subdirectory exists
  621.  * include special case of 'D:\' that Fsfirst does'nt handle correctly
  622.  * (this routine not needed for zmdm, as it is defined in common.c)
  623.  */
  624. int existd(name)
  625. register char *name;
  626. {
  627.     /* assuming the DTA buffer is already set up */
  628.     /* assumes drv_map has been read in drv_map externally */
  629.     extern long drv_map;
  630.     register int drive;
  631.     extern struct stat statbuf;
  632.     
  633.     if (Fsfirst(name , 0x0021|0x0010) == 0)
  634.     {
  635.         if((statbuf.st_mode & 0x0010) == 0x0010)
  636.             return TRUE;
  637.     }
  638.  
  639.     /* Gemdos doesn't like d:\ style dirs */
  640.     if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
  641.     {
  642.         drive = name[0];
  643.         if(isupper(drive))
  644.             drive = tolower(drive);
  645.  
  646.         drive = drive - 'a';
  647.         if((drv_map & (1L << drive)) == 0)
  648.             return FALSE;
  649.         else
  650.             return TRUE;
  651.     }
  652.     /* Nor does Gemdos understand '.' or '..' */
  653.     /* Hey Atari, don't you guys ever test anything */
  654.     if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
  655.        (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
  656.         return TRUE;
  657.  
  658.     return FALSE;
  659. }
  660.  
  661. int MAIN(argc, argv)
  662. int argc;
  663. char **argv;
  664. {
  665.     register int i;
  666.     
  667.     for(i = 0; i < argc; i++)
  668.         printf("%d:\t%s\n", i, argv[i]);
  669.  
  670.  
  671.     return(0);
  672. }
  673.  
  674.  
  675. struct stat statbuf;      /* Disk Transfer address for Find first etc */
  676. long drv_map;
  677.  
  678. #ifdef MWC
  679. long _stksize = 128L * 1024L;
  680. #endif
  681.  
  682. main(argc, argv)
  683. int argc;
  684. char **argv;
  685. {
  686.     /* Set up Dta */
  687.     Fsetdta(&statbuf);
  688.     drv_map = Drvmap();
  689.  
  690.     exit(expandargs(MAIN, argc, argv));
  691. }
  692.  
  693. #endif /* TEST */
  694.